import 'package:flutter/material.dart';
import 'bitmap.dart';
import 'canvas_view.dart';
import 'curtain_light_model.dart';

num getMinValue(num a, num b) => a > b ? b : a;

num getMaxValue(num a, num b) => a > b ? a : b;

class CanvasEdit extends StatefulWidget {
  const CanvasEdit({
    Key? key,
    this.minScale = 0.1,
    this.maxScale = 3.0,
    required this.amount,
    required this.directionType,
    required this.sizeBox,
    required this.displayX,
    required this.displayY,
    required this.color,
    required this.canvasType,
    required this.bitmap,
    required this.onCallbackBitmap,
  }) : super(key: key);

  final double minScale;
  final double maxScale;
  final int amount;
  final DiyDeviceDirectionType directionType;
  final Size sizeBox;
  final int displayX;
  final int displayY;
  final Color color;
  final CanvasType canvasType;
  final Bitmap bitmap;
  final ValueChanged<Bitmap> onCallbackBitmap;

  @override
  State<CanvasEdit> createState() => CanvasEditState();
}

class CanvasEditState extends State<CanvasEdit>with SingleTickerProviderStateMixin {
  late Color color = widget.color;
  late CanvasType canvasType = widget.canvasType;
  late Bitmap bitmap = widget.bitmap;
  late DiyDeviceDirectionType directionType = widget.directionType;
  late TransformationController _controller;
  late AnimationController _flashController;
  late Animation animation;
  late double side;
  late double canvasWidth;
  late double canvasHeight;

  // double scale = 0.2;

  int hideCountX = -1;
  int hideCountY = -1;

  bool isTouch = false;
  double x = -1;
  double y = -1;

  Offset? offset;
  Offset startOffset = Offset.zero;

  @override
  void initState() {
    int minSize =
        getMinValue(widget.displayX, widget.displayY).toDouble().toInt();
    side = widget.sizeBox.width / minSize;
    canvasWidth = widget.displayX * side;
    canvasHeight = widget.displayY * side;
    _flashController = AnimationController(duration: const Duration(milliseconds: 1000),vsync: this)
    ..addListener(() {
      setState((){

      });
    })
    ..addStatusListener((status) {
      setState((){
        if(_flashController.isCompleted){
          _flashController.reverse();
        }else{

        }
      });
    });
    animation = Tween(begin:0.0,end:1.0).animate(_flashController);
    _flashController.forward();
    if (widget.amount == 1) {
      double y = (widget.sizeBox.height - canvasWidth) * 0.5;
      Matrix4 matrix4 = Matrix4.translationValues(0, y, 0);
      _controller = TransformationController(matrix4);
    } else {
      double scale = 0.5;
      if (widget.amount == 2) {
        scale = 0.7;
      }

      late Matrix4 matrix4;
      if (directionType == DiyDeviceDirectionType.vertical) {
        double x = (canvasWidth - canvasWidth * scale) * 0.5;
        double y;
        if (canvasHeight > widget.sizeBox.height) {
          y = canvasHeight * 0.5 - (widget.sizeBox.height * 0.5) * 0.9;
        } else {
          y = widget.sizeBox.height * 0.5;
        }
        matrix4 = Matrix4.translationValues(x, y, 0)..scale(scale, scale);
      } else {
        double x;
        if (canvasWidth > widget.sizeBox.width) {
          x = canvasWidth * 0.5 - (widget.sizeBox.width * 0.5) * 0.9;
        } else {
          x = widget.sizeBox.width * 0.5;
        }

        double y;
        if (widget.sizeBox.height > canvasHeight) {
          y = (widget.sizeBox.height - canvasHeight * scale) * 0.5;
        } else {
          y = (canvasHeight - canvasHeight * scale) * 0.5;
        }

        matrix4 = Matrix4.translationValues(x, y, 0)..scale(scale, scale);
      }

      _controller = TransformationController(matrix4);
    }
    super.initState();
  }

  @override
  void didUpdateWidget(covariant CanvasEdit oldWidget) {
    if (oldWidget.color != widget.color ||
        oldWidget.canvasType != widget.canvasType ||
        oldWidget.bitmap != widget.bitmap) {
      setState(() {
        color = widget.color;
        canvasType = widget.canvasType;
        bitmap = widget.bitmap;
      });
    }

    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    double h = widget.directionType == DiyDeviceDirectionType.horizontal
        ? widget.sizeBox.height
        : canvasHeight;
    return OverflowBox(
      minWidth: canvasWidth,
      maxWidth: canvasWidth,
      minHeight: h,
      maxHeight: h,
      alignment: Alignment.center,
      child: InteractiveViewer(
        transformationController: _controller,
        // boundaryMargin:
        // EdgeInsets.all(getMinValue(canvasWidth, canvasHeight).toDouble()),
        boundaryMargin: EdgeInsets.symmetric(
          horizontal: canvasWidth,
          vertical: canvasHeight,
        ),
        minScale: widget.minScale,
        maxScale: widget.maxScale,
        panEnabled: canvasType == CanvasType.move,
        scaleEnabled: canvasType == CanvasType.move,
        onInteractionStart:
            canvasType == CanvasType.move ? onInteractionStart : null,
        onInteractionUpdate:
            canvasType == CanvasType.move ? onInteractionUpdate : null,
        onInteractionEnd:
            canvasType == CanvasType.move ? onInteractionEnd : null,
        child: Stack(
          children: [
            GestureDetector(
              behavior: HitTestBehavior.translucent,
              // onTapDown: canvasType != CanvasType.move ? onTapDown : null,
              onPanStart: canvasType != CanvasType.move ? onPanStart : null,
              onPanUpdate: canvasType != CanvasType.move ? onPanUpdate : null,
              onPanEnd: canvasType != CanvasType.move ? onPanEnd : null,
              child: CustomPaint(
                size: Size(canvasWidth, canvasHeight),
                painter: CanvasEditPainter(
                  width: widget.sizeBox.width,
                  height: widget.sizeBox.height,
                  isTouch: isTouch,
                  displayX: widget.displayX,
                  displayY: widget.displayY,
                  side: side,
                  color: color,
                  bitmap: bitmap,
                  moveWidgetState: this,
                  hideCountX: hideCountX,
                  hideCountY: hideCountY,
                  x: x,
                  y: y,
                ),
              ),
            ),
            Text("Animation:${animation.value}",style: TextStyle(color: Colors.white),),
          ],
        ),
      ),
    );
  }

  void onInteractionStart(ScaleStartDetails details) {
    // setState(() {
    //   startOffset = details.localFocalPoint;
    // });
  }

  void onInteractionUpdate(ScaleUpdateDetails details) {
    // print('tag- /////////////////////////////////////////');
    // print('tag- localFocalPoint: ${details.localFocalPoint}');
    // print('tag- startOffset: $startOffset');
    // double dx = details.localFocalPoint.dx - startOffset.dx;
    // double dy = details.localFocalPoint.dy - startOffset.dy;
    //
    // setState(() {
    //   offset = Offset(dx, dy);
    // });
    // print('tag- offset: $offset');
    // print('tag- *****************************************');
    // print('tag- +++++++++++++++++++++++++++++++++++++++++');
  }

  void onInteractionEnd(ScaleEndDetails details) {}

  void onTapDown(TapDownDetails details) {
    if (canvasType == CanvasType.filling) {
      setState(() {
        isTouch = true;
      });
    } else if (canvasType == CanvasType.smear ||
        canvasType == CanvasType.erase) {
      setState(() {
        isTouch = true;
        hideCountX = details.localPosition.dx ~/ side;
        hideCountY = details.localPosition.dy ~/ side;
      });
    }
  }

  void onPanStart(DragStartDetails details) {
    if (canvasType == CanvasType.filling) {
      setState(() {
        isTouch = true;
      });
    } else if (canvasType == CanvasType.smear ||
        canvasType == CanvasType.erase) {
      setState(() {
        isTouch = true;
        hideCountX = details.localPosition.dx ~/ side;
        hideCountY = details.localPosition.dy ~/ side;
      });
    }
  }

  void onPanUpdate(DragUpdateDetails details) {
    if (canvasType == CanvasType.filling) {
      setState(() {
        isTouch = true;
      });
    } else if (canvasType == CanvasType.smear ||
        canvasType == CanvasType.erase) {
      setState(() {
        isTouch = true;
        hideCountX = details.localPosition.dx ~/ side;
        hideCountY = details.localPosition.dy ~/ side;
      });
    }
  }

  void onPanEnd(DragEndDetails details) {
    setState(() {
      isTouch = false;
    });
    widget.onCallbackBitmap.call(bitmap);
  }

  @override
  void dispose() {
    _controller.dispose();
    _flashController.dispose();
    super.dispose();
  }
}

class CanvasEditPainter extends CustomPainter {
  CanvasEditPainter({
    required this.width,
    required this.height,
    required this.isTouch,
    required this.displayX,
    required this.displayY,
    required this.side,
    required this.color,
    required this.bitmap,
    required this.moveWidgetState,
    required this.hideCountX,
    required this.hideCountY,
    required this.x,
    required this.y,
  }) {
    margin = 2.0;
    mPaint = Paint()
      ..strokeWidth = margin
      ..color = Colors.transparent
      ..style = PaintingStyle.stroke;
  }

  late Paint mPaint;
  late double margin;

  double width;
  double height;
  bool isTouch;
  int displayX;
  int displayY;
  double side;
  Color color;
  Bitmap bitmap;
  CanvasEditState moveWidgetState;

  int hideCountX;
  int hideCountY;
  double x;
  double y;

  @override
  void paint(Canvas canvas, Size size) {
    drawMatrix(canvas, size);
    addPixel(canvas, size);
    drawPixels(canvas, size);
  }

  void drawMatrix(Canvas canvas, Size size) {
    double lastX = 0;
    for (int i = 0; i <= displayX; i++) {
      Offset startX = Offset(lastX, 0);
      Offset endX = Offset(lastX, displayY * side);
      canvas.drawLine(startX, endX, mPaint);
      lastX += side;
    }
    double lastY = 0;
    for (int i = 0; i <= displayY; i++) {
      Offset startY = Offset(0, lastY);
      Offset endY = Offset(displayX * side, lastY);
      canvas.drawLine(startY, endY, mPaint);
      lastY += side;
    }
  }

  void addPixel(Canvas canvas, Size size) {
    if (hideCountX < 0 && hideCountX > displayX &&
        hideCountY < 0 && hideCountY > displayY || !isTouch) {
      return;
    }

    if (moveWidgetState.canvasType == CanvasType.filling) {
      for (int i = 0; i < displayX; i++) {
        for (int j = 0; j < displayY; j++) {
          bitmap.setPixel(dx: i, dy: j, color: color);
        }
      }
    } else if (moveWidgetState.canvasType == CanvasType.smear) {
      bitmap.setPixel(dx: hideCountX, dy: hideCountY, color: color);
    } else if (moveWidgetState.canvasType == CanvasType.erase) {
      bitmap.setPixel(
          dx: hideCountX, dy: hideCountY, color: bitmap.color);
    }
  }

  void drawPixels(Canvas canvas, Size size) {
    Paint transPaint = Paint();
    for (int i = 0; i < bitmap.x; i++) {
      for (int j = 0; j < bitmap.y; j++) {
        transPaint.color = bitmap.getPixel(dx: i, dy: j);
        double left = i * side + margin * 0.5;
        double top = j * side + margin * 0.5;
        double right = (i + 1) * side - margin * 0.5;
        double bottom = (j + 1) * side - margin * 0.5;
        canvas.drawRect(Rect.fromLTRB(left, top, right, bottom), transPaint);
      }
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
